package resources;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.ArrayList;
import java.util.Iterator;

import javax.imageio.ImageIO;

import utils.OOBB;

public class Sprite implements Res {

	public static final Sprite NULL = new Sprite();
	private String name;
	private ArrayList<Image> images = new ArrayList<Image>();
	private int xOrigin = 0, yOrigin = 0;

	// CONSTRUCTORS

	Sprite() {}

	/** Creates a <code>Sprite</code> with the name <code>name</code>. **/
	Sprite(String name) {
		this.name = name;
	}

	@Override
	public void read(File file) throws IOException {
		ArrayList<Image> imgs = new ArrayList<Image>();
		images.add(ImageIO.read(file));
		add(imgs);
		setOriginCenter();
	}

	// GETTERS

	/** Returns sub-image list length. **/
	public int length() {
		return images.size();
	}

	/** Returns first sub-image width. **/
	public int getWidth() {
		try {
			return images.get(0).getWidth(null);
		} catch (NullPointerException e) {
			return 0;
		}
	}

	/** Returns first sub-image height. **/
	public int getHeight() {
		try {
			return images.get(0).getHeight(null);
		} catch (NullPointerException e) {
			return 0;
		}
	}

	public float getRadius(int sprIndex, int sprIndexOOBB) {
		Image img = get(sprIndex, sprIndexOOBB);
		if (img == null)
			return 1;
		return (img.getWidth(null) + img.getHeight(null)) / 2;
	}

	public Rectangle2D getBounds(float x, float y, float xScale, float yScale, int index, int OOBB) {
		Image img = get(index, OOBB);
		return new Rectangle((int) x, (int) y, (int) (img.getWidth(null) * xScale), (int) (img.getHeight(null) * yScale));
	}

	// SUBIMAGES

	/**
	 * Returns the sub-image with the index <code>i</code>. Uses <code>outOfBoundsBehavior</code> to determine which image to return if <code>i</code> is out of the
	 * sub-image list bounds.
	 **/
	public Image get(int i, int outOfBoundsBehavior) {
		i = OOBB.transform(i, length(), outOfBoundsBehavior);
		if (i == -1)
			return null;
		try {
			return images.get(i);
		} catch (Exception e) {
			e.printStackTrace();
			return new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
		}
	}

	/** Returns whether the index <code>i</code> is exactly at the bounds of the sub-image list. **/
	public boolean isBound(int i) {
		return (i % length() == 0);
	}

	/** Adds <code>image</code> to the sub-image list. **/
	public void add(Image image) {
		images.add(image);
	}

	/** Adds all <code>images</code> to the sub-image list. **/
	public void add(Collection<Image> images) {
		images.addAll(images);
	}

	/** Removes the sub-image that matches <code>image</code>. **/
	public void remove(Image image) {
		images.remove(image);
	}

	/** Removes all the sub-images that match <code>images</code>. **/
	public void remove(Collection<Image> images) {
		images.removeAll(images);
	}

	/** Removes all the sub-images. **/
	public void clear() {
		images.clear();
	}

	// ORIGIN

	/** Sets the origin to <code>(x, y)</code>. **/
	public void setOrigin(int x, int y) {
		xOrigin = x;
		yOrigin = y;
	}

	/** Sets the origin to <code>(0, 0)</code>. **/
	public void resetOrigin() {
		xOrigin = 0;
		yOrigin = 0;
	}

	/** Sets the origin to the center of the first sub-image. **/
	public void setOriginCenter() {
		Image img = images.get(0);
		if (img != null)
			setOrigin(images.get(0).getWidth(null) / 2, images.get(0).getHeight(null) / 2);
		else
			resetOrigin();
	}

	/** Looks in the first sub-image in the sprite for a pixel with color <code>c</code>, then sets the origin to that pixel. **/
	public void setOrigin(Color c) {
		Image img = images.get(0);
		if (img != null)
			setOrigin(images.get(0).getWidth(null) / 2, images.get(0).getHeight(null) / 2);
		else
			resetOrigin();
	}

	/** Returns the <code>Sprite</code>'s x-origin. **/
	public int getXOrigin() {
		return xOrigin;
	}

	/** Returns the <code>Sprite</code>'s y-origin. **/
	public int getYOrigin() {
		return yOrigin;
	}

	// PAINT

	public void paint(Graphics2D g, float x, float y, int index, int OOBB, float xScale, float yScale, float angle) {
		Image img = get(index, OOBB);
		if (img == null)
			return;
		g.translate(-getXOrigin(), -getYOrigin());
		g.rotate(angle * Math.PI / 180, x + getXOrigin(), y + getYOrigin());
		g.drawImage(img, (int) x, (int) y, (int) (img.getWidth(null) * xScale), (int) (img.getHeight(null) * yScale), null);
		g.rotate(-angle * Math.PI / 180, x + getXOrigin(), y + getYOrigin());
		g.translate(getXOrigin(), getYOrigin());
	}

	// RES

	@Override
	public String getName() {
		return name;
	}

	@Override
	public void setName(String resName) {
		name = resName;
	}

	// STRINGS

	@Override
	public String toString() {
		return images.toString();
	}

}
